#!/bin/sh

#功能：PHS系统Fota系统组件，提供Fota包安装和安全一致性校验功能
#开发维护：Hihope Xi'an

# 初始化变量
INSTALL_FOTA=false
PACKAGE_PATH=""
ONLY_CHECK=false
ROLLBACK=false
SHOW_VERSION=false
SHOW_HELP=false

PACKAGE_REAL_PATH=""
STATUS_FILE=""
RUNNING_SLOT=""

# 初始化环境变量
ret=-1

#升级状态码	含义
CHECK_OK=101		#升级校验成功。
UPD_START=103		#升级开始。
UPD_ING=105			#升级中（带升级进度,例如，105&50）
UPD_END=107			#升级操作结束。
UPD_REBOOTED=108	#升级结束重启中
UPD_REBOOTING=109	#升级重启中。
UPD_OK=200			#升级成功
	
UPD_FAIL_MEMERR=501			#升级失败-内存池申请失败         
UPD_FAIL_CHECKERR=502		#升级失败-写后回读数据校验错误   
UPD_FAIL_BAKERR=503			#升级失败-备份数据校验失败       
UPD_FAIL_CACUERR=504		#升级失败-升级算法初始化错误     
UPD_FAIL_FSERR=505			#升级失败-文件系统错误           
UPD_FAIL_PACKERR=506		#升级失败-升级包格式错误         
UPD_FAIL_ROMSIZEERR=507		#升级失败-设备用于升级的内存不足 
UPD_FAIL_SRCCHKERR=508		#升级失败-升级源版本校验失败     
UPD_FAIL_AUTHERR=509		#升级失败-升级权限认证失败       
UPD_FAIL_FILENOTEXIST=510	#升级失败-升级包不存在           
UPD_FAIL_ROMERR=511			#升级失败-升级包存储空间不足     
UPD_FAIL_SUBDEVTIMEOUT=512	#升级失败-子设备升级超时         
UPD_FAIL_SUBDEVERR=513		#升级失败-子设备升级异常         
UPD_FAIL_OTHER=599			#升级失败-其他错误 


# 解析参数
while getopts ":p:icrsuS:vh" opt; do
  case ${opt} in
    p )
      PACKAGE_PATH=$OPTARG
      ;;
    i )
      INSTALL_FOTA=true
      ;;
    c )
      ONLY_CHECK=true
      ;;
    r )
      ROLLBACK=true
      ;;
    v )
      SHOW_VERSION=true
      ;;
    h )
      SHOW_HELP=true
      ;;
    \? )
      echo "Invalid option: -$OPTARG" >&2
      SHOW_HELP=true
      ;;
    : )
      echo "Invalid option: -$OPTARG requires an argument" >&2
      SHOW_HELP=true
      ;;
  esac
done
shift $((OPTIND -1))

# 打印帮助信息
function print_help() {
  echo "Usage: sysupdate [options]"
  echo "Options:"
  echo "  -p <xxx.tar.gz>    Fota包文件路径"
  echo "  -i                 安装Fota包"
  echo "  -c                 仅校验Fota包"
  echo "  -r                 回退到前一个版本"
  echo "  -v                 获取安装的程序的版本"
  echo "  -h                 打印帮助信息"
}

# 打印版本信息
function print_version() {
  echo "sysupdate version: 1.0.0"
}

# 写状态接口
function log_status() {
    local status_code="$1"
	if [ -f "${STATUS_FILE}" ];then
		echo "$(date +"%Y%m%d%H%M%S%3N"):${status_code}" >> "${STATUS_FILE}"
	fi
}

function get_pakcage_size() {
	stat -c%s updater
}

function check_userdata_size() {
	echo "正在检查用户分区空间..."
	#待实现
}

# 解析PACKAGE_NAME
function get_package_name() {
	local path="$1"
	PACKAGE_NAME=${path##*/}
	return 0
}

# 解析PACKAGE_REAL_PATH
function get_package_real_path() {
	local path="$1"

	case "$path" in
	  */*)
		PACKAGE_REAL_PATH="${path%/*}"
		;;
	  *)
		PACKAGE_REAL_PATH=$(pwd)
		;;
	esac
	
	if [ -n "${PACKAGE_REAL_PATH}" ];then
		if [ "${PACKAGE_REAL_PATH}" = "." ];then
			PACKAGE_REAL_PATH=$(pwd)
		fi
	fi
	
	return 0
}

# 解析APP_NAME
function get_app_name() {
	local path="$1"
	get_package_name ${path}
	if [ $? -eq 0 ]; then
		if [ -z "${PACKAGE_NAME}" ]; then
			return -1
		fi
		APP_NAME=${PACKAGE_NAME%%_*}
		return 0
	fi
	return -1
}


# 校验包
# 成功：0
# 失败：-1
function sha256_check() {
	local package_file=$1
	# 初始化配置文件
	if [ -n ${PACKAGE_REAL_PATH} ];then
	 if [ -n ${APP_NAME} ];then
		CONFIG_FILE=${PACKAGE_REAL_PATH}/install.json
	 fi
	fi

	if [ ! -f ${CONFIG_FILE} ];then
		echo "未找到配置文件！"
		return -1
	fi
	
	if [ ! -f ${package_file} ];then
		echo "未找到待验证文件！"
		return -1
	fi
	
	sha256=$(busybox sha256sum ${package_file})
	hash_value=$(echo "${sha256}" | cut -d' ' -f1)
	 
	while IFS= read -r line
	do
		trimmed_line="${line#"${line%%[![:space:]]*}"}"
		trimmed_line="${trimmed_line%"${trimmed_line##*[![:space:]]}"}"
	 
		if echo "$trimmed_line" | grep -q sha256; then
			value=$(echo "$trimmed_line" | sed -E 's/.*"sha256Hex":"([^"]*)".*/\1/')
			sha_list+=("${value}")
		fi
	done < ${CONFIG_FILE}


	for value in "${sha_list[@]}"; do
		if [ "${hash_value}" = "${value}" ];then
			echo "SHA256校验成功。"
			log_status ${CHECK_OK}
			return 0
		fi
	done
	
	return -1
}

# 安装Fota包
function perform_install() {
  # 安装所需空间检查，待完善，实际当前ota包解压后大小213M
  check_userdata_size
  
  # 解析path
  get_app_name ${PACKAGE_PATH}
  get_package_real_path ${PACKAGE_PATH}
  
  # 创建缓存  
  if [ -n ${PACKAGE_REAL_PATH} ];then
	 INSTALL_TEMP=${PACKAGE_REAL_PATH}/.temp
  fi
  
  if [ ! -e ${INSTALL_TEMP} ]; then
	mkdir -p ${INSTALL_TEMP}
  else
	rm -rf ${INSTALL_TEMP}
	mkdir -p ${INSTALL_TEMP}
  fi
  
  # 初始化状态文件
  if [ -n ${PACKAGE_REAL_PATH} ];then
	 if [ -n ${APP_NAME} ];then
		STATUS_FILE=${PACKAGE_REAL_PATH}/${PACKAGE_NAME}_upgradeStatus.ini
	 fi
  fi
  
  if [ ! -f ${STATUS_FILE} ];then
  	echo "未找到状态上报文件"
  fi
  
  if [ -f ${STATUS_FILE} ];then
  	#初始化清空STATUS_FILE
  	cat /dev/null > ${STATUS_FILE}
  fi
  
  echo "正在安装软件包: ${PACKAGE_REAL_PATH}/${PACKAGE_NAME}"
  
  # Sha256检查
  sha256_check ${PACKAGE_REAL_PATH}/${PACKAGE_NAME}
  ret=$?
  if [ ${ret} -ne 0 ]; then
  	echo "ERROR: Sha256检查."
  	return ${ret}
  fi
  
  log_status ${UPD_START}
  
  if [ -f ${PACKAGE_REAL_PATH}/${PACKAGE_NAME} ]; then
	echo "正在解压安装包..."
	tar -zxf ${PACKAGE_REAL_PATH}/${PACKAGE_NAME} -C ${INSTALL_TEMP}
	ret=$?
	if [ ${ret} -ne 0 ]; then
		echo "ERROR: 解压安装包错误."
		log_status ${UPD_FAIL_FSERR}
		# 清理临时安装文件
		rm -rf ${INSTALL_TEMP}
		return ${ret}
	fi
	
	echo "正在安装升级包..."
	log_status "${UPD_ING}&20"
	
	cd ${INSTALL_TEMP}
	if [ -f "install.sh" ]; then
		./install.sh
		ret=$?
	else
		echo "ERROR: 升级包错误."
		log_status ${UPD_FAIL_PACKERR}
		ret=${UPD_FAIL_PACKERR}	
	fi
	
	if [ ${ret} -ne 0 ]; then
		echo "安装失败！ error code：${ret}"
		log_status ${UPD_FAIL_OTHER}
		# 清理临时安装文件
		rm -rf ${INSTALL_TEMP}
		return ${ret}
	fi
	
	# 至此安装成功
	echo "安装成功!"
	log_status "${UPD_ING}&100"
	log_status ${UPD_END}
	log_status ${UPD_REBOOTING}
	
	# 清理临时安装文件
	rm -rf ${INSTALL_TEMP}

	echo "系统重启..."
	reboot
  else
  	echo "ERROR: 升级包未找到."
	log_status ${UPD_FAIL_FILENOTEXIST}
	ret=${UPD_FAIL_FILENOTEXIST}	
  	return ${ret}
  fi
}

function perform_only_check() {
  # 解析path
  get_app_name ${PACKAGE_PATH}
  get_package_real_path ${PACKAGE_PATH}

  echo "正在校验软件包: ${PACKAGE_REAL_PATH}/${PACKAGE_NAME}"
  
  # Sha256检查
  sha256_check ${PACKAGE_REAL_PATH}/${PACKAGE_NAME}
  ret=$?
  if [ ${ret} -ne 0 ]; then
  	echo "ERROR: Sha256检查."
  	return ${ret}
  fi
  
  echo "校验通过：OK"
}

function get_running() {
	boot_helper setrunning 1>/dev/null
	boot_info=$(boot_helper getinfo)
	
	temp=${boot_info#*boot.running_slot: }
	RUNNING_SLOT=${temp:0:1}

	if [ -z ${RUNNING_SLOT} ]; then
		echo "ERROR: no running_slot found."
		return ${FAIL}
	fi
	
	return ${SUCCESS}
}

# 回退到前一个版本，会自动重启
function roll_back() {
  get_running
  if [ ${RUNNING_SLOT} = "a" ]; then
  	echo "正在回退到 B ..."
  	boot_helper setslot b
  	if [ $? -ne 0 ]; then
  		echo "回退失败."
  		exit -1
  	fi
  fi
  
  if [ ${RUNNING_SLOT} = "b" ]; then
  	echo "正在回退到 A ..."
  	boot_helper setslot a
  	if [ $? -ne 0 ]; then
  		echo "回退失败."
  		exit -1
  	fi
  fi
  
  echo "回退成功!"
  reboot
}

# 根据解析的参数执行相应的操作
if [ "$INSTALL_FOTA" = true ]; then
  if [ -z "$PACKAGE_PATH" ]; then
    echo "Error: 安装软件包时，请提供软件包路径..." >&2
    SHOW_HELP=true
  else
    perform_install
  fi
elif [ "$ONLY_CHECK" = true ]; then
  if [ -z "$PACKAGE_PATH" ]; then
    echo "Error: 检查软件包时，请提供软件包路径..." >&2
    SHOW_HELP=true
  else
    perform_only_check
  fi
elif [ "$ROLLBACK" = true ]; then
  roll_back
elif [ "$SHOW_VERSION" = true ]; then
  print_version
else
  echo "无效参数."
  SHOW_HELP=true
fi

# 如果需要打印帮助信息，则打印
if [ "$SHOW_HELP" = true ]; then
  print_help
fi
